package com.atguigu.gmall.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.common.result.Result;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.gateway.constant.RedisConst;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.file.Path;

/**
 * @author Mamba
 * @version 1.0
 * @Description
 *  自定义全局过滤器
 *   判断用户是否登录
 *  1、不用登录
 *  2、可登录或不登录
 *  3、必须登录
 *  4、内部资源 不允许访问
 * @date 2021/1/3 18:42
 */
@Component//交由Spring来管理
public class LoginGlobalFilter implements GlobalFilter, Ordered {
    //路径匹配
    private AntPathMatcher antPathMatcher = new AntPathMatcher();
    //常量
    public static final String TOKEN ="token";
    //临时用户Id
    public static final String USERTEMPID = "userTempId";
    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${auth.url}")
    private String[] authUrls;
   //过滤器方式
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //exchange  交换机   == 请求对象  响应对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        System.out.println("request.getPath:"+request.getPath());//http://www.gmall.com/list.html?keyword=手机
        //     //www.gmall.com/list.html?keyword=手机
        System.out.println(request.getURI().getRawSchemeSpecificPart());
        //获取请求头
        //获取Cookie
        //MultiValueMap<String, HttpCookie> cookies = request.getCookies();
        System.out.println("request.getURI.getPath:"+request.getURI().getPath());
        System.out.println("getHostString:"+request.getRemoteAddress().getHostString());
        System.out.println("getHostName:"+request.getRemoteAddress().getHostName());

        ///////////////////以下为正式代码///////////////////////////////////////////
        //哪些微服务走网关  ： 用户微服务 商品微服务 搜索微服务 异步 同步
        //  VUE  访问网关  路由 某一个微服务  异步的 Json串
        //  搜索微服务 Feign远程调用 商品微服务 异步 json
        // Html 访问网关  路由 页面微服务 页面渲染 同步
        //结论： 如下
        //1:内部资源  转发  商品微服务 /inner 不允许
        //2：异步：未登录  返回值 Result.fail  LOGIN_AUTH(208, "未登陆"), JSON格式字符串 返回
        //页面上208时 将早早准备好弹出层 弹出来 让用户去登录
        //3：同步： 未登录  重定向  去登录页面

        //当前请求的路径
        String path = request.getURI().getPath();
        if (antPathMatcher.match("/**/inner/**", path)){
            //内部资源 209 无权限访问
            return out(response,ResultCodeEnum.PERMISSION);
        }

        //必须登录 获取用户Id
        String userId = getUserId(request);

        //异步请求资源中 必须登录 /**/auth/**
        if (antPathMatcher.match("/**/auth/**",path)){
            if (StringUtils.isEmpty(userId)){
                //未登录
                return out(response,ResultCodeEnum.LOGIN_AUTH);
            }
        }
        //同步 trade.html  pay.html ....  /list.html  /search  /trade.html
        for (String authUrl : authUrls) {
            if (path.indexOf(authUrl) != -1 &&StringUtils.isEmpty(userId)){
                //未登录 重定向到登录页面
                response.setStatusCode(HttpStatus.SEE_OTHER);//重定向
                //重定向到哪个URL
                try {
                    response.getHeaders().add(HttpHeaders.LOCATION,
                            "//passport.gmall.com/login.html?originUrl=" +
                                    URLEncoder.encode(
                                            request.getURI().getRawSchemeSpecificPart(),"utf-8"
                                    ));
                } catch (UnsupportedEncodingException e){
                    e.printStackTrace();
                }
                return response.setComplete();//响应完成
            }
        }
        //判断如果用户ID存在 传递用户ID 购物车是不登录就访问
        if(null != userId){
            //request.getHeaders().add("userId",userId);运行此行代码报错 不可以修改请求头
            //新的请求 将请求头 设置用户Id 转发到购物车微服务
            request.mutate().header("userId",userId);
        }
        //判断是否有临时用户Id  safdfwdf3252dafd
        String userTempId = getUserTempId(request);
        if (null != userTempId){
            request.mutate().header("userTempId",userTempId);
        }


        //放行   进入下一个过滤器 转发微服务
        return chain.filter(exchange);
    }

    //统一异步请求返回值
    public Mono<Void> out(ServerHttpResponse response, ResultCodeEnum resultCodeEnum){
        Result<Object> result = Result.build(null, resultCodeEnum);
        //转成Json串
        String json = JSONObject.toJSONString(result);
        //响应
        DataBufferFactory dataBufferFactory = response.bufferFactory();
        DataBuffer dataBuffer = dataBufferFactory.wrap(json.getBytes());
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE,
                "application/json;charset=UTF-8");
        return response.writeWith(Mono.just(dataBuffer));
    }

    //获取临时用户Id
    private String getUserTempId(ServerHttpRequest request) {
        //1:请求头中
        String userTempId = request.getHeaders().getFirst(USERTEMPID);
        if (StringUtils.isEmpty(userTempId)) {
            //2：Cookie中
            HttpCookie cookie = request.getCookies().getFirst(USERTEMPID);
            if (null != cookie) {
                userTempId = cookie.getValue();
            }
        }
        return userTempId;
    }

    //获取用户Id
    private String getUserId(ServerHttpRequest request){
        //1:请求头中
        String token = request.getHeaders().getFirst(TOKEN);
        if (StringUtils.isEmpty(token)){
            //2:Cookie中
            HttpCookie cookie = request.getCookies().getFirst(TOKEN);
            if (null != cookie){
                token = cookie.getValue();
            }
        }
        if (token != null){
            //获取到token 查询Redis中 从获取用户ID
            if (redisTemplate.hasKey(RedisConst.USER_LOGIN_KEY_PREFIX + token)){
                return (String) redisTemplate.opsForValue().get(
                        RedisConst.USER_LOGIN_KEY_PREFIX + token);
            }
        }
        return null;
    }

    //排序    默认有9大全局过滤器  + 当前自定义过滤器 == 共10个全局过滤器
    // 最小 整数最小   Integer.MIN_VALUE     -- -1 0 1 ------      最大 整数最大
    // 最小 执行优先级最高                                             最低
    @Override
    public int getOrder() {
        return 0;
    }
}
